package cn.zysheep.httpclient;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.IOException;

/**
 * Apache httpclient POST 请求使用
 *
 */
@SuppressWarnings("all")
public class HttpPostTest {

    /**
     * http post 请求，设置请求正文参数
     */
    @Test
    public void testPost1() {
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = null;
        CloseableHttpResponse httpResponse = null;
        try {
            //1、创建 CloseableHttpClient 同步请求对象
            httpClient = HttpClientBuilder.create().build();

            // 2、HttpPost(final String uri)：创建 http post 请求对象, 设置请求头信息
            String url = "https://news.ssp.qq.com/app";
            httpPost = new HttpPost(url);
            httpPost.setHeader("Content-Type", "application/json;charset=utf8");

            // 3、设置 post 请求正文参数
            String postParams = "{\"adReqData\":{\"chid\":9,\"adtype\":0,\"uin\":null,\"qq_openid\":\"\",\"slot\":[{\"loid\":\"1\",\"cur\":0,\"channel\":\"world\",\"orders_info\":[],\"article_id\":\"\",\"refresh_type\":1,\"current_rot\":\"\",\"seq\":\"\",\"seq_loid\":\"\"}],\"netstatus\":\"unknown\",\"pf\":\"pc\",\"appversion\":\"200717\",\"plugin_news_cnt\":20,\"plugin_page_type\":\"\",\"plugin_text_ad\":false,\"plugin_bucket_id\":\"\"}}";
            httpPost.setEntity(new StringEntity(postParams, "UTF-8"));

            // 4、CloseableHttpResponse execute(final HttpUriRequest request)：执行请求
            // 如果连接不上服务器，则抛出:java.net.ConnectException: Connection refused: connect
            httpResponse = httpClient.execute(httpPost);

            // 5、获取响应结果, 状态码 200 表示请求成功
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            System.out.println("响应状态码：" + statusCode);
            if (statusCode == 200) {
                HttpEntity httpEntity = httpResponse.getEntity();
                // 使用指定的字符编码解析响应消息实体
                String feedback = EntityUtils.toString(httpEntity, "UTF-8");
                System.out.println("feedback：" + feedback);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            /**
             * consume(final HttpEntity entity)：确保实体内容已完全使用，并且内容流（如果存在）已关闭。
             *  httpResponse.close()：关闭此流并释放与之关联的所有系统资源。如果流已关闭，则调用此方法无效。
             */
            try {
                if (httpResponse != null) {
                    EntityUtils.consume(httpResponse.getEntity());
                    httpResponse.close();
                }
                //无论成功与否,都要释放连接并终止
                if (httpPost != null && !httpPost.isAborted()) {
                    httpPost.releaseConnection();
                    httpPost.abort();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * http post 请求，文件上传
     */
    @Test
    public void testPost2() {
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = null;
        CloseableHttpResponse httpResponse = null;
        try {
            //1、创建 CloseableHttpClient 同步请求对象
            httpClient = HttpClientBuilder.create().build();

            // 2、HttpPost(final String uri)：创建 http post 请求对象
            String url = "http://localhost:8080/file/upload?info=单文件上传";
            //String url = "http://localhost:8080/file/uploads?info=多文件上传";
            httpPost = new HttpPost(url);

            // 3、设置上传的文件参数，无论服务器端接收的单文件还是多文件，都可以上传.
            File file = new File("F:\\Temp\\Test.java");
            FileBody fileBody = new FileBody(file);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            //服务器接收的单文件时 MultipartFile file，属性名必须与服务器参数名称一致
            //服务器接收的多文件时 List<MultipartFile> files，属性名不强制与服务器参数名称一致
            builder.addPart("file", fileBody);
            HttpEntity entity = builder.build();
            httpPost.setEntity(entity);

            // 4、CloseableHttpResponse execute(final HttpUriRequest request)：执行请求
            // 如果连接不上服务器，则抛出:java.net.ConnectException: Connection refused: connect
            httpResponse = httpClient.execute(httpPost);

            // 5、获取响应结果, 状态码 200 表示请求成功
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            System.out.println("响应状态码：" + statusCode);
            if (statusCode == 200) {
                HttpEntity httpEntity = httpResponse.getEntity();
                // 使用指定的字符编码解析响应消息实体
                String feedback = EntityUtils.toString(httpEntity, "UTF-8");
                System.out.println("feedback：" + feedback);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            /**
             * consume(final HttpEntity entity)：确保实体内容已完全使用，并且内容流（如果存在）已关闭。
             *  httpResponse.close()：关闭此流并释放与之关联的所有系统资源。如果流已关闭，则调用此方法无效。
             */
            try {
                if (httpResponse != null) {
                    EntityUtils.consume(httpResponse.getEntity());
                    httpResponse.close();
                }
                //无论成功与否,都要释放连接并终止
                if (httpPost != null && !httpPost.isAborted()) {
                    httpPost.releaseConnection();
                    httpPost.abort();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
